package com.jht.bletool2java.characteristic.ftms;

import android.bluetooth.BluetoothGattCharacteristic;
import android.util.Log;

import androidx.annotation.Keep;

import com.jht.bletool2java.characteristic.TranslateData;
import com.jht.bletool2java.util.ByteUtil;
import com.jht.bletool2java.util.ComputerUtil;

import top.codestudy.annotation_uuid.MyUUID;

//判断处理ok
@Keep
@MyUUID(uuid = "00002ad1-0000-1000-8000-00805f9b34fb")
public class RowerData implements TranslateData {

    private static RowerData data;
    private final String TAG = "RowerData";
    byte[] value1;
    private byte[] flags = new byte[2];
    private byte[] strokeRate;
    private byte[] strokeCount;
    private byte[] average_stroke_rate;
    private byte[] total_distance;
    private byte[] instantaneous_pace;
    private byte[] average_pace;
    private byte[] instantaneous_power;
    private byte[] average_power;
    private byte[] resistance_level;
    private byte[] total_energy;
    private byte[] energy_per_hour;
    private byte[] energy_per_minute;
    private byte[] heart_rate;
    private byte[] metabolic_equivalent;
    private byte[] elapsed_time;
    private byte[] remaining_time;
    private boolean StrokeRateAndStrokeCount = false;
    private boolean averageStroke = false;
    private boolean totalDistance = false;
    private boolean insPace = true;
    private boolean averagePace = true;
    private boolean insPower = true;
    private boolean averagePower = true;
    private boolean resistanceLevel = true;
    private boolean energy = false;
    private boolean heartRate = false;
    private boolean metabolic = false;
    private boolean elapsedTime = false;
    private boolean remainingTime = false;
    private boolean flagChecked = false;
    private int expect_data_length = 0;
    private byte[] valueData;
    //是否是非法数据
    private boolean isInvalidData = false;

    public RowerData() {
    }

    public RowerData(BluetoothGattCharacteristic characteristic) {
        byte[] value = characteristic.getValue();
        value1 = value;
        valueData = value;
        parseData(value);
        for (int i = 0; i < value.length; i++) {
            Log.i(TAG, "RowerData: i = " + i + "; ox" + Integer.toHexString(ByteUtil.byte1ToInt(value[i])));
        }
    }

    public static RowerData getInstance() {
        data = new RowerData();
        return data;
    }

    public void parseData(byte[] buffer) {
        Log.i(TAG, "parseData: buffer.length " + buffer.length);
        System.arraycopy(buffer, 0, flags, 0, 2);
        checkEachFieldIfSupported();
        parseEachSupportedFeature(buffer);
    }

    private void checkEachFieldIfSupported() {
        if (flagChecked) {
            return;
        }
        byte firstbyte = (byte) (flags[0] ^ 0xFE); // 0xFE means all features are supported in 1st byte;
        byte secondbyte = (byte) (flags[1] ^ 0xFF); // 0x1F mean all features are supported in 2nd byte;

        expect_data_length = 2;

        if (isBitZero(firstbyte, 0)) {
            //Stroke Rate And Stroke Count is supported
            StrokeRateAndStrokeCount = true;
            strokeRate = new byte[1];
            strokeCount = new byte[2];
            expect_data_length += 3;
            Log.d(TAG, "Stroke Rate And Stroke Count is supported");
        } else {
            Log.e(TAG, "数据过多！显示数据不可靠！");
        }
        if (isBitZero(firstbyte, 1)) {
            //averageStroke is supported
            averageStroke = true;
            average_stroke_rate = new byte[1];
            expect_data_length += 1;
            Log.d(TAG, "averageStroke is supported");
        }

        if (isBitZero(firstbyte, 2)) {
            //totalDistance is supported
            totalDistance = true;
            total_distance = new byte[3];
            expect_data_length += 3;
            Log.d(TAG, "totalDistance is supported");
        }
        if (isBitZero(firstbyte, 3)) {
            //Instantaneous Pace is supported
            insPace = true;
            instantaneous_pace = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "Instantaneous Pace is supported");
        }
        if (isBitZero(firstbyte, 4)) {
            //averagePace is supported
            averagePace = true;
            average_pace = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "averagePace is supported");
        }
        if (isBitZero(firstbyte, 5)) {
            //Instantaneous Power is supported
            insPower = true;
            instantaneous_power = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "Instantaneous Power is supported");
        }
        if (isBitZero(firstbyte, 6)) {
            //Average Poweris supported
            averagePower = true;
            average_power = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "Average Power is supported");
        }
        if (isBitZero(firstbyte, 7)) {
            //  Resistance Level supported
            resistanceLevel = true;
            resistance_level = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "  Resistance Level is supported");
        }
        if (isBitZero(secondbyte, 0)) {
            //Expended Energy is supported
            energy = true;
            total_energy = new byte[2];
            energy_per_hour = new byte[2];
            energy_per_minute = new byte[1];
            expect_data_length += 5;
            Log.d(TAG, "Expended Energy is supported");
        }
        if (isBitZero(secondbyte, 1)) {
            // heartRate are supported
            heartRate = true;
            heart_rate = new byte[1];
            expect_data_length += 1;
            Log.d(TAG, "heartRate is supported");
        }

        if (isBitZero(firstbyte, 2)) {
            //metabolic is supported
            metabolic = true;
            metabolic_equivalent = new byte[1];
            expect_data_length += 1;
            Log.d(TAG, "metabolic is supported");
        }

        if (isBitZero(secondbyte, 3)) {
            //elapsed time is supported
            elapsedTime = true;
            elapsed_time = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "elapsed time is supported");
        }
        if (isBitZero(secondbyte, 4)) {
            //remaining time is supported
            remainingTime = true;
            remaining_time = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "remaining time is supported");
        }

        flagChecked = true;
    }

    /**
     * @param value, the xor result, 0 means feature is supported. 1 means feature is not supported
     * @param bit,   the bit of value to check
     * @return
     */
    private boolean isBitZero(byte value, int bit) {
        int power2 = (int) Math.pow(2, bit);
        int tmp = value & power2;
        if (tmp == 0) {
            return true;
        } else {
            return false;
        }
    }

    private void parseEachSupportedFeature(byte[] buffer) {
        if (buffer.length < expect_data_length) {
            isInvalidData = true;
            Log.d(TAG, "buffer length is " + buffer.length);
            Log.d(TAG, "expect data length is " + expect_data_length);
            return;
        }

        int startIndex = 2;
        if (StrokeRateAndStrokeCount) {
            System.arraycopy(buffer, startIndex, strokeRate, 0, 1);
            startIndex += 1;
            System.arraycopy(buffer, startIndex, strokeCount, 0, 2);
            startIndex += 2;
        }
        if (averageStroke) {
            System.arraycopy(buffer, startIndex, average_stroke_rate, 0, 1);
            startIndex += 1;
        }
        if (totalDistance) {
            System.arraycopy(buffer, startIndex, total_distance, 0, 3);
            startIndex += 3;
        }
        if (insPace) {
            System.arraycopy(buffer, startIndex, instantaneous_pace, 0, 2);
            startIndex += 2;
        }
        if (averagePace) {
            System.arraycopy(buffer, startIndex, average_pace, 0, 2);
            startIndex += 2;
        }
        if (insPower) {
            System.arraycopy(buffer, startIndex, instantaneous_power, 0, 2);
            startIndex += 2;
        }
        if (averagePower) {
            System.arraycopy(buffer, startIndex, average_power, 0, 2);
            startIndex += 2;
        }
        if (resistanceLevel) {
            System.arraycopy(buffer, startIndex, resistance_level, 0, 2);
            startIndex += 2;
        }
        if (energy) {
            System.arraycopy(buffer, startIndex, total_energy, 0, 2);
            startIndex += 2;
            System.arraycopy(buffer, startIndex, energy_per_hour, 0, 2);
            startIndex += 2;
            System.arraycopy(buffer, startIndex, energy_per_minute, 0, 1);
            startIndex += 1;
        }
        if (heartRate) {
            System.arraycopy(buffer, startIndex, heart_rate, 0, 1);
            startIndex += 1;
        }
        if (metabolic) {
            System.arraycopy(buffer, startIndex, metabolic_equivalent, 0, 1);
            startIndex += 1;
        }
        if (elapsedTime) {
            System.arraycopy(buffer, startIndex, elapsed_time, 0, 2);
            startIndex += 2;
        }
        if (remainingTime) {
            System.arraycopy(buffer, startIndex, remaining_time, 0, 2);
        }
    }

    public double getStrokeRate() {
        if (StrokeRateAndStrokeCount) {
            return ComputerUtil.multiply(ByteUtil.byte1ToInt(strokeRate[0]), "0.5");
        } else {
            return -9999;
        }
    }

    public int getStrokeCount() {
        if (StrokeRateAndStrokeCount) {
            return ByteUtil.bytes2ToInt(strokeCount, 0);
        } else {
            return -9999;
        }
    }

    public double getAverageStroke() {
        if (averageStroke) {
            return ComputerUtil.multiply(ByteUtil.byte1ToInt(average_stroke_rate[0]), "0.5");
        } else {
            return -9999;
        }
    }

    public int getTotalDistance() {
        if (totalDistance) {
            return ByteUtil.byte3ToInt(total_distance, 0);
        } else {
            return -9999;
        }
    }

    public int getInsPace() {
        if (insPace) {
            return ByteUtil.bytes2ToInt(instantaneous_pace, 0);
        } else {
            return -9999;
        }
    }

    public int getAveragePace() {
        if (averagePace) {
            return ByteUtil.bytes2ToInt(average_pace, 0);
        } else {
            return -9999;
        }
    }

    public int getInsPower() {
        if (insPower) {
            return ByteUtil.bytes2ToInt(instantaneous_power, 0);
        } else {
            return -9999;
        }
    }

    public int getAveragePower() {
        if (averagePower) {
            return ByteUtil.bytes2ToInt(average_power, 0);
        } else {
            return -9999;
        }
    }

    public int getResistanceLevel() {
        if (resistanceLevel) {
            return ByteUtil.bytes2ToInt(resistance_level, 0);
        } else {
            return -9999;
        }
    }

    public int getTotalEnergy() {
        if (energy) {
            return ByteUtil.bytes2ToInt(total_energy, 0);
        } else {
            return -9999;
        }
    }

    public int getEnergyPerHour() {
        if (energy) {
            return ByteUtil.bytes2ToInt(energy_per_hour, 0);
        } else {
            return -9999;
        }
    }

    public int getEnergyPerMinute() {
        if (energy) {
            return ByteUtil.byte1ToInt(energy_per_minute[0]);
        } else {
            return -9999;
        }
    }

    public int getHeartRate() {
        if (heartRate) {
            return ByteUtil.byte1ToInt(heart_rate[0]);
        } else {
            return -9999;
        }
    }

    public double getMetabolicEquivalent() {
        if (metabolic) {
            return ComputerUtil.multiply(ByteUtil.byte1ToInt(metabolic_equivalent[0]), "0.1");
        } else {
            return -9999;
        }
    }

    public int getElapedTime() {
        if (elapsedTime) {
            return ByteUtil.bytes2ToInt(elapsed_time, 0);
        } else {
            return -9999;
        }
    }

    public int getRemainingTime() {
        if (remainingTime) {
            return ByteUtil.bytes2ToInt(remaining_time, 0);
        } else {
            return -9999;
        }
    }

    public String convert2String() {
        return "Stroke Rate is  " + getStrokeRate()
                + "  stroke_per_minute;\n Stroke Count is  " + getStrokeCount()
                + "  ;\n average stroke rate is  " + getAverageStroke()
                + "  stroke_per_minute ;\n TotalEnergy is  " + getTotalEnergy()
                + "  Calorie ;\n HeartRate is  " + getHeartRate()
                + "  bpm ;\n elapsed time is  " + getElapedTime()
                + "  second;\n Resistance Level is  " + getResistanceLevel()
                + "  ;\n TotalDistance is  " + getTotalDistance()
                + "  metre;\n RemainingTime is  " + getRemainingTime()
                + "  second;\n AveragePower is  " + getAveragePower()
                + "  watt;\n InsPower is  " + getInsPower()
                + "  watt;\n InsPace is  " + getInsPace()
                + "  second;\n AveragePace is  " + getAveragePace()
                + "  second;\n EnergyPerHour is  " + getEnergyPerHour()
                + "  kilogram_calorie;\n EnergyPerMinute is   " + getEnergyPerMinute()
                + "  kilogram_calorie;\n Metabolic Equivalent : " + getMetabolicEquivalent()
                + ";\n ";
    }

    @Override
    public String merge(TranslateData translateData) {
        RowerData temp = (RowerData) translateData;
        if (temp.StrokeRateAndStrokeCount) {
            this.strokeRate = temp.strokeRate;

            this.strokeCount = temp.strokeCount;
            this.StrokeRateAndStrokeCount = true;
        }
        if (temp.averageStroke) {
            this.average_stroke_rate = temp.average_stroke_rate;
            this.averageStroke = true;
        }
        if (temp.totalDistance) {
            this.total_distance = temp.total_distance;
            this.totalDistance = true;
        }
        if (temp.insPace) {
            this.instantaneous_pace = temp.instantaneous_pace;
            this.insPace = true;
        }
        if (temp.averagePace) {
            this.average_pace = temp.average_pace;
            this.averagePace = true;
        }
        if (temp.insPower) {
            this.instantaneous_power = temp.instantaneous_power;
            this.insPower = true;
        }
        if (temp.averagePower) {
            this.average_power = temp.average_power;
            this.averagePower = true;
        }
        if (temp.resistanceLevel) {
            this.resistance_level = temp.resistance_level;
            this.resistanceLevel = true;
        }
        if (temp.energy) {
            this.total_energy = temp.total_energy;

            this.energy_per_hour = temp.energy_per_hour;

            this.energy_per_minute = temp.energy_per_minute;
            this.energy = true;
        }
        if (temp.heartRate) {
            this.heart_rate = temp.heart_rate;
            this.heartRate = true;
        }
        if (temp.metabolic) {
            this.metabolic_equivalent = temp.metabolic_equivalent;
            this.metabolic = true;
        }
        if (temp.elapsedTime) {
            this.elapsed_time = temp.elapsed_time;
            this.elapsedTime = true;
        }
        if (temp.remainingTime) {
            this.remaining_time = temp.remaining_time;
            this.remainingTime = true;
        }

        return null;
    }

    @Override
    public boolean hasMoreData() {
        return !StrokeRateAndStrokeCount;
    }

    @Override
    public byte[] getData() {
        return valueData;
    }

    @Override
    public boolean isInvalidData() {
        return isInvalidData;
    }

    @Override
    public void parseData(BluetoothGattCharacteristic characteristic, byte[] value) {
        init();
        value1 = value;
        valueData = value;
        parseData(value);
        for (int i = 0; i < value.length; i++) {
            Log.i(TAG, "RowerData: i = " + i + "; ox" + Integer.toHexString(ByteUtil.byte1ToInt(value[i])));
        }
    }

    private void init() {
        StrokeRateAndStrokeCount = false;
        averageStroke = false;
        totalDistance = false;
        insPace = true;
        averagePace = true;
        insPower = true;
        averagePower = true;
        resistanceLevel = true;
        energy = false;
        heartRate = false;
        metabolic = false;
        elapsedTime = false;
        remainingTime = false;
        flagChecked = false;
        expect_data_length = 0;
        //是否是非法数据
        isInvalidData = false;
    }
}
